package me.mononin.factory.data;

import android.support.annotation.NonNull;

import com.raizlabs.android.dbflow.structure.BaseModel;
import com.raizlabs.android.dbflow.structure.database.transaction.QueryTransaction;

import net.qiujuer.genius.kit.reflect.Reflector;

import java.lang.reflect.Type;
import java.util.LinkedList;
import java.util.List;

import me.mononin.common.factory.data.DataSource;
import me.mononin.common.factory.data.DbDataSource;
import me.mononin.common.utils.CollectionUtil;
import me.mononin.factory.data.helper.DbHelper;
import me.mononin.factory.model.db.BaseDbModel;
import me.mononin.factory.model.db.User;
import me.mononin.factory.persistence.Account;

/**
 * 基础数据仓库
 * 实现基础数据操作
 */
public abstract class BaseDbRepository<Data extends BaseDbModel<Data>> implements DbDataSource<Data>
        , DbHelper.ChangedListener<Data> ,QueryTransaction.QueryResultListCallback<Data>{
    //和Presenter交互的回调
    private SucceedCallback<List<Data>> callback;
    //当前缓存的数据
    protected final LinkedList<Data> dataList = new LinkedList<>();
    //当前泛型所对应的类型
    private Class<Data> dataClass;

    public BaseDbRepository(){
        //获取传递泛型实际类
        Type[] types = Reflector.getActualTypeArguments(BaseDbRepository.class,this.getClass());
        dataClass = (Class<Data>) types[0];
    }

    @Override
    public void load(SucceedCallback<List<Data>> callback) {
        //保存回调
        this.callback = callback;
        registerDbChangedListener();
    }

    @Override
    public void dispose() {
        //取消监听，销毁数据
        this.callback = null;
        DbHelper.removeChangedListener(dataClass,this);
        dataList.clear();
    }
    //数据库统一保存通知
    @Override
    public void onDataSave(Data... list) {
        //数据变更时的操作
        boolean isChanged = false;
        if (list==null||list.length==0){
            return;
        }
        for (Data data : list) {
            //是关注的人，同时不是自己
            if (isRequired(data)){
                insertOrUpdate(data);
                isChanged = true;
            }
        }

        if (isChanged){
            notifyDataChange();
        }
    }
    //数据库统一删除通知
    @Override
    public void onDataDelete(Data... list) {
        //数据删除时的操作
        boolean isChanged = false;
        for (Data data : list) {
            if (dataList.remove(data)){
                isChanged = true;
            }
        }

        if (isChanged){
            notifyDataChange();
        }
    }

    //数据回调操作方法
    @Override
    public void onListQueryResult(QueryTransaction transaction, @NonNull List<Data> tResult) {
        if (tResult.size()==0){
            tResult.clear();
            notifyDataChange();
        }

        Data[] users = CollectionUtil.toArray(tResult,dataClass);
        onDataSave(users);
    }

    /**
     * 插入或更新用户数据
     * @param data 用户数据
     */
    protected void insertOrUpdate(Data data){
        int index = indexOf(data);
        if (index>=0){
            replace(index,data);
        }else {
            insert(data);
        }
    }

    /**
     * 更新指定位置用户集用户数据
     * @param index 下标
     * @param data 用户数据
     */
    protected void replace(int index,Data data){
        dataList.remove(index);
        dataList.add(index,data);
    }

    //插入用户到用户集
    protected void insert(Data data){
        dataList.add(data);
    }

    /**
     * 判断是否包含当前用户
     * @param newData 用户
     * @return 返回当前用户所在用户集的下标
     */
    private int indexOf(Data newData){
        int index = -1;
        for (Data data : dataList) {
            index++;
            if (data.isSame(newData)){
                return index;
            }
        }
        return -1;
    }

    /**
     * 检查一个用户是否是我关注的用户
     * @param data 需要判断的用户
     * @return True为我已关注的用户
     */
    protected abstract boolean isRequired(Data data) ;

    /**
     * 为当前数据表添加监听器
     */
    protected void registerDbChangedListener(){
        DbHelper.addChangedListener(dataClass,this);
    }

    //通知界面刷新方法
    private void notifyDataChange(){
        SucceedCallback<List<Data>> callback = this.callback;
        if (callback!=null){
            callback.onDataLoaded(dataList);
        }
    }
}
